Skip to main content

9. Verifying Revoked Credentials

In order to make sure a credential is not revoked, when making a proof request, it is important to include the non_revoked field. This field defines a time frame where a verifier wants a credential to be valid i.e. not revoked.

To define this time frame, the non_revoked field has two subfields from (optional) and to, both accepting dates in seconds since the Unix epoch. In most cases, the current time should be used, as the verifier is typically interested in credentials that are valid at the time of sending the proof request. Unless, of course, the verifier's use case requires some specific time.

NB: The non-revoked field can be passed as an empty object ("non-revoked":{}), then the application will use the current time when sending the proof request.

The non-revoked field can be specified for all requested attributes (global):

...
"indy_proof_request": {
"non_revoked": {
"from": 0,
"to": 1714727880
},
"requested_attributes": {
...

or it can be added to specific attributes individually:

...
"indy_proof_request": {
"requested_attributes": {
"surname": { "name": "Surname", "non_revoked":{"to":1714727880}},
...

When both are specified simultaneously, the attribute-specific one will take priority:

...
"indy_proof_request": {
"non_revoked":{"to":1714727999},
"requested_attributes": {
"surname": { "name": "Surname", "non_revoked":{"to":1714727880}},
"name": {"name": "Name"}
...

In the above snippet, Surname will be checked against the "non_revoked": {"to": 1714727880} value, while Name will be checked against the global value "non_revoked": {"to": 1714727999}.

Verifying non-revoked before the revocation date

When specifying a non_revoked time frame that precedes the revocation time, the proof request will pass. This is by design as the credential was valid in that time frame.

Let's demonstrate:

Listing the holder's credentials:

GET /wallet/credentials

Response:

{
"results": [
{
"attrs": {
"Surname": "Alice",
"Age": "25",
"Name": "Holder"
},
"cred_def_id": "BzDvB7StHDD1HQKczybHWC:3:CL:16:Demo_Person",
"cred_rev_id": "1",
"referent": "47b18eb8-35f1-4d89-865e-d8355bec77fe",
"rev_reg_id": "BzDvB7StHDD1HQKczybHWC:4:BzDvB7StHDD1HQKczybHWC:3:CL:16:Demo_Person:CL_ACCUM:73890f4d-42fd-42c5-9a2e-b39fe0358fc6",
"schema_id": "Pp7wcmoHgeMb3td99E5Yo8:2:Person:0.1.0"
}
]
}

The holder can check the revocation status of their credential:

GET /wallet/credentials/47b18eb8-35f1-4d89-865e-d8355bec77fe/revocation-status

Response:

{
"revoked": true
}

The holder can see that their credential is revoked. Let's try a verification flow with this credential.

In this example, the verifier sends a request specifying a date/time (2024-05-07 9:00 AM) before the revocation:

POST /verifier/send-request

Request body:

{
"protocol_version": "v2",
"comment": "string",
"trace": true,
"type": "indy",
"indy_proof_request": {
"non_revoked": {
"from": 0,
"to": 1715065200
},
"requested_attributes": {
"surname": { "name": "Surname" },
"name": { "name": "Name" },
"age": { "name": "Age" }
},
"requested_predicates": {}
},
"save_exchange_record": true,
"connection_id": "cf45f341-57ad-42bc-b727-6f35e311e7e7"
}

The holder responds:

POST /verifier/accept-request

Request body:

{
"proof_id": "v2-142c6cd8-a84c-441f-b099-2b39ed6d2099",
"type": "indy",
"indy_presentation_spec": {
"requested_attributes": {
"age": {
"cred_id": "47b18eb8-35f1-4d89-865e-d8355bec77fe",
"revealed": true
},
"name": {
"cred_id": "47b18eb8-35f1-4d89-865e-d8355bec77fe",
"revealed": true
},
"surname": {
"cred_id": "47b18eb8-35f1-4d89-865e-d8355bec77fe",
"revealed": true
}
},
"requested_predicates": {},
"self_attested_attributes": {}
},
"save_exchange_record": true
}

The verifier will receive the following webhook on the proofs topic:

{
"wallet_id": "9a7adafe-3a09-499b-a171-6d39a426bf9e",
"topic": "proofs",
"origin": "tenant faber",
"group_id": "GroupA",
"payload": {
"connection_id": "cf45f341-57ad-42bc-b727-6f35e311e7e7",
"created_at": "2024-05-07T07:21:58.776430Z",
"error_msg": null,
"parent_thread_id": null,
"presentation": null,
"presentation_request": null,
"proof_id": "v2-635d106c-7777-4368-bc57-d24f7f878343",
"protocol_version": "v2",
"role": "verifier",
"state": "done",
"thread_id": "b8c70d2b-fe36-4216-9d0a-7c30a6fceb5e",
"updated_at": "2024-05-07T07:29:10.445048Z",
"verified": true
}
}

As you can see, the holder's credential is valid ("verified": true), since the verifier requested a non_revoked timestamp before the revocation took place.

Verifying non-revoked after revocation date

Now, the verifier specifies a date/time (2024-05-07 9:11 AM) after the revocation occurred

POST /verifier/send-request

Request body:

{
"protocol_version": "v2",
"comment": "string",
"trace": true,
"type": "indy",
"indy_proof_request": {
"non_revoked": {
"from": 0,
"to": 1715065860
},
"requested_attributes": {
"surname": { "name": "Surname" },
"name": { "name": "Name" },
"age": { "name": "Age" }
},
"requested_predicates": {}
},
"save_exchange_record": true,
"connection_id": "cf45f341-57ad-42bc-b727-6f35e311e7e7"
}

The holder responds:

POST /verifier/accept-request

Request body:

{
"proof_id": "v2-1894498a-579b-4dd9-9875-856c7f3f4381",
"type": "indy",
"indy_presentation_spec": {
"requested_attributes": {
"age": {
"cred_id": "47b18eb8-35f1-4d89-865e-d8355bec77fe",
"revealed": true
},
"name": {
"cred_id": "47b18eb8-35f1-4d89-865e-d8355bec77fe",
"revealed": true
},
"surname": {
"cred_id": "47b18eb8-35f1-4d89-865e-d8355bec77fe",
"revealed": true
}
},
"requested_predicates": {},
"self_attested_attributes": {}
},
"save_exchange_record": true
}

The verifier will receive the following webhook:

{
"wallet_id": "9a7adafe-3a09-499b-a171-6d39a426bf9e",
"topic": "proofs",
"origin": "tenant faber",
"group_id": "GroupA",
"payload": {
"connection_id": "cf45f341-57ad-42bc-b727-6f35e311e7e7",
"created_at": "2024-05-07T08:02:41.229378Z",
"error_msg": null,
"parent_thread_id": null,
"presentation": null,
"presentation_request": null,
"proof_id": "v2-6aaf1b87-45aa-49ee-8e2e-24fe79663fa6",
"protocol_version": "v2",
"role": "verifier",
"state": "done",
"thread_id": "53fe75f8-f4b8-4e22-ae1a-b3a13f2f41c9",
"updated_at": "2024-05-07T08:18:33.060039Z",
"verified": false
}
}

As you can see, the verification has now failed ("verified": false).

Congratulations! You now know how to verify if credentials are revoked or not. 🥳🎉